package com.dingreading.cloud.admin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.admin.dto.RealUsableNumDto;
import com.dingreading.cloud.admin.entity.WhStockIn;
import com.dingreading.cloud.admin.entity.table.WhStockInTableDef;
import com.dingreading.cloud.admin.mapper.WhStockInMapper;
import com.dingreading.cloud.admin.service.WhStockInService;
import com.dingreading.cloud.common.util.NepUtil;
import com.dingreading.cloud.common.util.PageUtil;
import com.dingreading.cloud.common.util.QueryFiledUtil;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 服务层实现。
 *
 * @author Administrator
 * @since 2023-11-22
 */
@Service
public class WhStockInServiceImpl extends BaseServiceImpl<WhStockInMapper, WhStockIn, WhStockInTableDef> implements WhStockInService {

    @Override
    protected WhStockInTableDef getTable() {
        return WhStockInTableDef.whStockIn;
    }

    @Resource
    WhStockInMapper stockInMapper;

    @Override
    public Page<WhStockIn> pageList(PageUtil pageUtil, String keyword, Integer status, String beginDate, String endDate) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(keyword)) {
            condition.and(table.purchaseCode.like(keyword)
                    .or(table.inCode.like(keyword))
                    .or(table.goodsName.like(keyword))
                    .or(table.goodsTypeName.like(keyword))
                    .or(table.supplierName.like(keyword))
            );
        }

        if (status != null)
            condition.and(table.status.eq(status));
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginate(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper);
    }

    @Override
    public Page<WhStockIn> returnList(PageUtil pageUtil, String keyword, Integer status) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(keyword)) {
            condition.and(table.purchaseCode.like(keyword)
                    .or(table.inCode.like(keyword))
                    .or(table.goodsName.like(keyword))
                    .or(table.goodsTypeName.like(keyword))
                    .or(table.supplierName.like(keyword))
            );
        }

        if (status != null)
            condition.and(table.status.eq(status));
        else
            condition.and(table.status.in(Lists.newArrayList(1, -1)));

        QueryWrapper wrapper = QueryWrapper.create()
                .where(condition)
                .orderBy(table.id.desc());

        return getMapper().paginate(Page.of(pageUtil.getPage(), pageUtil.getRows()), wrapper);
    }

    @Override
    public int dropData(String inCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.eq(inCode))
                .and(table.status.eq(2));
        return getMapper().deleteByCondition(condition);
    }

    @Override
    public List<WhStockIn> getByPurchaseId(Long purchaseGoodsId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.purchaseGoodsId.eq(purchaseGoodsId));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public long getByPurchaseIdCnt(Long purchaseGoodsId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.purchaseGoodsId.eq(purchaseGoodsId));
        return getMapper().selectCountByCondition(condition);
    }

    @Override
    public WhStockIn getByInCode(String inCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.eq(inCode));
        return getMapper().selectOneByCondition(condition);
    }

    @Override
    public List<WhStockIn> getByInCodes(List<String> inCodes) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.in(inCodes));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public long getPurchaseCodeCnt(String purchaseCode, Integer status) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.purchaseCode.eq(purchaseCode));
        if (status != null)
            condition.and(table.status.eq(status));
        return getMapper().selectCountByCondition(condition);
    }

    @Override
    public int getGoodsTypeUsableNum(Long goodsTypeId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.goodsTypeId.eq(goodsTypeId))
                .and(table.usableNum.gt(0))
                .and(table.status.eq(1));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(QueryMethods.sum(table.usableNum))
                .from(table)
                .where(condition);

        Integer integer = getMapper().selectObjectByQueryAs(wrapper, Integer.class);
        return NepUtil.nullToZero(integer);
    }

    @Override
    public List<WhStockIn> getOkGoodsTypeUsableNumLog(Long goodsTypeId, Integer buyNum) {
        return stockInMapper.getOkGoodsTypeUsableNumLog(goodsTypeId, buyNum);
    }

    @Override
    public int updateUsableNum(Map<Long, Integer> map, String time) {
        List<Long> ids = Lists.newArrayList(map.keySet());
        return stockInMapper.updateUsableNum(map, ids, time);
    }

    @Override
    public List<WhStockIn> getByPurchaseCode(String purchaseCode) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.purchaseCode.eq(purchaseCode));
        return getMapper().selectListByCondition(condition);
    }

    @Override
    public int getRealNumCnt(Long purchaseGoodsId) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.purchaseGoodsId.eq(purchaseGoodsId))
                .and(table.status.eq(1));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(QueryMethods.sum(table.realNum))
                .from(table)
                .where(condition);

        Integer integer = getMapper().selectObjectByQueryAs(wrapper, Integer.class);
        return NepUtil.nullToZero(integer);
    }

    @Override
    public boolean setOk(String inCode, Long operatorId, String operator, Integer usableNum, double inAmount, Date time) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.eq(inCode))
                .and(table.status.eq(2));

        return UpdateChain.of(WhStockIn.class)
                .set(table.status, 1)
                .set(table.statusName, "入库完成")
                .set(table.usableNum, usableNum)
                .set(table.inAmount, inAmount)
                .set(table.operatorId, operatorId)
                .set(table.operator, operator)
                .set(table.okTime, time)
                .where(condition)
                .update();
    }

    @Override
    public boolean setOk(String inCode, String operatorUid, String operator, Integer usableNum, double inAmount, Date time) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.eq(inCode))
                .and(table.status.eq(2));

        return UpdateChain.of(WhStockIn.class)
                .set(table.status, 1)
                .set(table.statusName, "入库完成")
                .set(table.usableNum, usableNum)
                .set(table.inAmount, inAmount)
                .set(table.operatorUid, operatorUid)
                .set(table.operator, operator)
                .set(table.okTime, time)
                .where(condition)
                .update();
    }


    @Override
    public boolean setReturn(String inCode, String operatorUid, String operator, String remark, int returnNum, double returnPrice, Date time) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inCode.eq(inCode));
        condition.and(table.status.eq(1));
        return UpdateChain.of(WhStockIn.class)
                .set(table.status, -1)
                .set(table.statusName, "入库已退回")
                .set(table.returnerUid, operatorUid)
                .set(table.returner, operator)
                .set(table.returnNum, returnNum)
                .set(table.returnPrice, returnPrice)
                .set(table.returnRemark, remark)
                .set(table.returnTime, time)
                .where(condition)
                .update();
    }

    @Override
    public Map<String, RealUsableNumDto> getRealNumAndUsableNumByPurchaseCode(List<String> purchaseCodes) {
        List<JSONObject> jsonObjectList = stockInMapper.getRealNumAndUsableNumByPurchaseCode(purchaseCodes);

        List<RealUsableNumDto> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(jsonObjectList)) {
            for (JSONObject jsonObject : jsonObjectList) {
                RealUsableNumDto dto = new RealUsableNumDto();
                dto.setCode(jsonObject.getString("purchaseCode"));
                dto.setRealNum(jsonObject.getString("realNumCnt"));
                dto.setUsableNum(jsonObject.getString("usableNumCnt"));
                list.add(dto);
            }
        }

        Map<String, RealUsableNumDto> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list)) {
            map = list.stream().collect(Collectors.toMap(RealUsableNumDto::getCode, Function.identity()));
        }
        return map;
    }

    @Override
    public Map<Long, Integer> getStockNumMap(List<Long> goodsTypeIds) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.goodsTypeId.in(goodsTypeIds))
                .and(table.usableNum.gt(0))
                .and(table.status.eq(1));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(table.goodsTypeId, QueryMethods.sum(table.usableNum).as("usableNum"))
                .from(table)
                .where(condition)
                .groupBy(table.goodsTypeId);

        List<Row> rows = getMapper().selectRowsByQuery(wrapper);

        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        if (CollectionUtils.isNotEmpty(rows)) {
            for (Row row : rows) {
                Long aLong = row.getLong("goods_type_id");
                Integer integer = row.getInt("usableNum");
                if (aLong != null)
                    map.put(aLong, NepUtil.nullToZero(integer));
            }
        }
        return map;
    }

    @Override
    public Map<Long, Integer> getInNum(List<Long> goodsTypeIds) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inType.eq(1))
                .and(table.status.eq(1))
                .and(table.goodsTypeId.in(goodsTypeIds));

        QueryWrapper wrapper = QueryWrapper.create()
                .select(QueryMethods.sum(table.realNum).as("cnt"), table.goodsTypeId)
                .from(table)
                .where(condition)
                .groupBy(table.goodsTypeId);

        List<Row> list = getMapper().selectRowsByQuery(wrapper);

        Map<Long, Integer> map = new HashMap<>();
        for (Long goodsTypeId : goodsTypeIds) {
            map.put(goodsTypeId, 0);
        }
        if (CollectionUtils.isNotEmpty(list)) {
            for (Row row : list) {
                Long goodsTypeId = row.getLong("goods_type_id");
                Integer cnt = row.getInt("cnt");
                map.put(goodsTypeId, NepUtil.nullToZero(cnt));
            }
        }
        return map;
    }

    @Override
    public Map<Long, List<WhStockIn>> listByGoodsTypeIdAndAddTimeBetween(List<Long> goodsTypeIds, String beginDate, String endDate) {
        QueryCondition condition = QueryCondition.createEmpty();
        condition.and(table.inType.eq(1))
                .and(table.status.eq(1))
                .and(table.goodsTypeId.in(goodsTypeIds));

        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

        List<WhStockIn> list = getMapper().selectListByCondition(condition);
        Map<Long, List<WhStockIn>> map = new HashMap<>();
        if (CollectionUtils.isNotEmpty(list)) {
            map = list.stream().collect(Collectors.groupingBy(WhStockIn::getGoodsTypeId));
        }
        return map;
    }

    @Override
    public List<WhStockIn> exportList(String keyword, String beginDate, String endDate) {
        QueryCondition condition = QueryCondition.createEmpty();
        if (StringUtils.isNotBlank(keyword))
            condition.and(table.inCode.like(keyword)
                    .or(table.goodsName.like(keyword))
                    .or(table.goodsTypeName.like(keyword))
                    .or(table.purchaseCode.like(keyword))
            );
        if (StringUtils.isNotBlank(beginDate) && StringUtils.isNotBlank(endDate))
            condition.and(table.addTime.between(QueryFiledUtil.appendMin00(beginDate), QueryFiledUtil.appendMin24(endDate)));

        return getMapper().selectListByCondition(condition);
    }

}
